package crmdna.client.group;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.List;
import java.util.Set;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.googlecode.objectify.ObjectifyFilter;

import crmdna.client.contactdetail.ContactDetail.ContactDetailProp;
import crmdna.client.group.Group.GroupProp;
import crmdna.client.member.Member;
import crmdna.client.member.MemberCore.MemberProp;
import crmdna.client.user.User;
import crmdna.client.user.User.Action;
import crmdna.client.user.User.ResourceType;
import crmdna.client.user.UserCore.UserProp;
import crmdna.common.APIException;
import crmdna.common.APIResponse.Status;
import crmdna.crmdna.Client;

public class GroupTest {
	
	private final LocalServiceTestHelper datastoreHelper =
		        new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
		        .setApplyAllHighRepJobPolicy());
	
	private final String client = "isha";
 	private final String invalidClient = "invalid";
 	private final String validUser = "valid@login.com";
 	private final String userWithPermission = "withpermission@login.com";
 	GroupProp chennai;
	
    @Before
    public void setUp() {
        datastoreHelper.setUp();  
        ObjectifyFilter.complete();
        
        Client.create(client);
        
        //can call getAll without any groups
    	List<GroupProp> centers = Group.getAll(client);
    	assertEquals(0, centers.size());
    	
        chennai = Group.create(client, "Chennai", User.SUPER_USER);
        assertEquals(1, chennai.groupId);
       
        User.create(client, validUser, chennai.groupId, User.SUPER_USER);
        assertEquals(1, User.get(client, validUser).toProp().userId);
        
        User.create(client, userWithPermission, chennai.groupId, User.SUPER_USER);
        assertEquals(2, User.get(client, userWithPermission).toProp().userId);
        
        User.addOrDeletePrivilege(client, userWithPermission, ResourceType.GROUP, 0, 
        		Action.WRITE, true, User.SUPER_USER);    
        User.addOrDeletePrivilege(client, userWithPermission, ResourceType.USER, 0, 
        		Action.WRITE, true, User.SUPER_USER);    
    }

    @After
    public void tearDown() {       
    	ObjectifyFilter.complete();
        datastoreHelper.tearDown();
    }
    
    @Test
    public void createTest() {    	
    	
    	GroupProp prop = Group.create(client, "Singapore", userWithPermission);
    	assertTrue(prop.groupId == 2); //one already created in the set up method
    	
    	prop = Group.safeGet(client, prop.groupId).toProp();
    	assertEquals("singapore", prop.name);
    	assertEquals("Singapore", prop.displayName);    	    
    	
    	//cannot create duplicate
    	try {
    		Group.create("isha", "SINGAPORE", User.SUPER_USER);
    		assertTrue(false);
    	} catch (APIException e) {
    		assertEquals(Status.ERROR_RESOURCE_ALREADY_EXISTS, e.statusCode);
    	}
    	
    	//group ids should be in sequence
    	prop = Group.create(client, "Malaysia/KL", userWithPermission);
    	assertEquals(3, prop.groupId);
    	prop = Group.create(client, "Australia/Sydney", userWithPermission);
    	assertEquals(4, prop.groupId);
    	prop = Group.create(client, "Australia/Melbourne", userWithPermission);
    	assertEquals(5, prop.groupId);
    	
    	prop = Group.safeGet(client, 3).toProp();
    	assertEquals("malaysia/kl", prop.name);
    	prop = Group.safeGet(client, 4).toProp();
    	assertEquals("Australia/Sydney", prop.displayName);
    	prop = Group.safeGet(client, 5).toProp();
    	assertEquals("Australia/Melbourne", prop.displayName);
    	assertEquals("australia/melbourne", prop.name);
    	
    	//access control
    	try {
    		Group.create("isha", "Malaysia/Johor", validUser);
    		assertTrue(false);
    	} catch (APIException e) {
    		assertEquals(Status.ERROR_INSUFFICIENT_PERMISSION, e.statusCode);
    	}
    	
    	//client should be valid
    	try {
    		Group.create(invalidClient, "Singapore", User.SUPER_USER);
    		assertTrue(false);
    	} catch (APIException e) {
    		assertEquals(Status.ERROR_RESOURCE_DOES_NOT_EXIST, e.statusCode);
    	}    	
    }
    
    @Test
    public void safeGetTest() {   
    	
    	GroupProp group = Group.create(client, "Singapore", userWithPermission);
    	assertTrue(group.groupId != 0);
    	
    	group = Group.safeGet("isha", group.groupId).toProp();
    	assertEquals("singapore", group.name);
    	assertEquals("Singapore", group.displayName);	
    	
    	//exception for non existing group
    	try {
    		Group.safeGet("isha", group.groupId + 20939); //non existant
    		assertTrue(false);
    	} catch (APIException ex) {
    		assertEquals(Status.ERROR_RESOURCE_DOES_NOT_EXIST, ex.statusCode);
    	}
    }
    
    @Test
    public void ensureValidGroupIdsTest() {
    	assertTrue(false);
    }
    
    @Test
    public void renameTest() {    	
    	GroupProp sgp = Group.create("isha", "Singapore", userWithPermission);
    	Group.create("isha", "Sydney", userWithPermission);
    	
    	try {
    		Group.rename("isha", sgp.groupId, "sydney", userWithPermission);
    		assertTrue(false);
    	} catch (APIException ex) {
    		assertEquals(Status.ERROR_RESOURCE_ALREADY_EXISTS, ex.statusCode);
    	}
    	
    	//can change case and rename
    	sgp = Group.rename("isha", sgp.groupId, "singapore", userWithPermission);
    	sgp = Group.safeGet("isha", sgp.groupId).toProp();
    	assertEquals("singapore", sgp.name);
    	assertEquals("singapore", sgp.displayName);
    	
    	sgp = Group.rename("isha", sgp.groupId, "Sgp", userWithPermission);
    	sgp = Group.safeGet("isha", sgp.groupId).toProp();
    	assertEquals("sgp", sgp.name);
    	assertEquals("Sgp", sgp.displayName);    
    	
    	try {
    		Group.rename("isha", sgp.groupId, "Sgp", validUser);
    		assertTrue(false);
    	} catch (APIException ex) {
    		assertEquals(Status.ERROR_INSUFFICIENT_PERMISSION, ex.statusCode);
    	}
    	
    }
    
    @Test
    public void getAllTest() {    	    	    
    	Group.create("isha", "Sydney", userWithPermission);
    	Group.create("isha", "Singapore", userWithPermission);    	
    	ObjectifyFilter.complete();
    	
    	List<GroupProp> groups = Group.getAll("isha");
    	assertEquals(3, groups.size()); //chennai already created in set up method
    	//should be sorted
    	assertEquals("singapore", groups.get(1).name);
    	assertEquals("Singapore", groups.get(1).displayName);
    	assertEquals("sydney", groups.get(2).name);
    	assertEquals("Sydney", groups.get(2).displayName);    	    	    	
    }
    
    @Test
    public void getAllGroupIdsTest() {
    	Set<Long> all = Group.getAllGroupIds("isha");
    	
    	assertEquals(1, all.size());
    	assertTrue(all.contains(chennai.groupId));
    	
    	GroupProp sydney = Group.create("isha", "Sydney", userWithPermission);
    	GroupProp sgp = Group.create("isha", "Singapore", userWithPermission);    	
    	ObjectifyFilter.complete();
    	
    	all = Group.getAllGroupIds("isha");
    	assertEquals(3, all.size());
    	assertTrue(all.contains(chennai.groupId));
    	assertTrue(all.contains(sydney.groupId));
    	assertTrue(all.contains(sgp.groupId));    	
    }
    
    public void deleteTest() {
    	GroupProp sgp = Group.create(client, "Sgp", User.SUPER_USER);
    	GroupProp kl = Group.create(client, "KL", User.SUPER_USER);
    	
    	//test permission
    	try {
    		Group.delete(client, sgp.groupId, validUser);
    		assertTrue(false);
    	} catch (APIException ex) {
			assertEquals(Status.ERROR_INSUFFICIENT_PERMISSION, ex.statusCode);
		}
    	
    	UserProp userProp = User.create(client, "sgpuser@login.com", sgp.groupId, User.SUPER_USER);
    	ContactDetailProp contact = new ContactDetailProp();
    	contact.email = "email1@email.com";
    	MemberProp memberProp = Member.create(client, sgp.groupId, contact, validUser);
    	Member.addOrDeleteCenter(client, memberProp.memberId, kl.groupId, true, validUser);
    	
    	//There should not be any user for that center    	
    	try {
    		Group.delete(client, sgp.groupId, userWithPermission);
    		assertTrue(false);
    	} catch (APIException ex) {
			assertEquals(Status.ERROR_PRECONDITION_FAILED, ex.statusCode);
		}
    	
    	User.updateGroup(client, userProp.email, kl.groupId, userWithPermission);
    	assertEquals(0, User.getAllForGroup(client, sgp.groupId).size());
    	
    	//There should not be any member for that center
    	try {
    		Group.delete(client, sgp.groupId, userWithPermission);
    		assertTrue(false);
    	} catch (APIException ex) {
			assertEquals(Status.ERROR_PRECONDITION_FAILED, ex.statusCode);
		}
    	
    	Member.addOrDeleteCenter(client, memberProp.memberId, sgp.groupId, false, validUser);
    	assertEquals(0, Member.getAllForGroup(client, sgp.groupId, validUser).size());
    	
    	assertEquals("force failure", true, false);    	
    }
    
    @Test
    public void toPropTest() {
    	GroupEntity entity = new GroupEntity();
    	entity.groupId = 123l;
    	entity.displayName = "Singapore";
    	entity.name = entity.displayName.toLowerCase();
    	
    	GroupProp prop = entity.toProp();
    	assertEquals(123, prop.groupId);
    	assertEquals("Singapore", prop.displayName);
    	assertEquals("singapore", prop.name);    	    	
    }
}
